<?php
// $Id: listing_location_handler_filter_proximity.inc,v 1.3 2011/01/16 06:10:22 newzeal Exp $
// NY zip 10099  	
/**
 * General proximity filter for location latitude/longitude.
 */
class listing_location_handler_filter_proximity extends views_handler_filter {
  // This is always single, because of the distance field's possible dependency
  // on it.
  var $no_single = TRUE;

  function option_definition() {
    $options = parent::option_definition();
    $options['type'] = array('default' => 'latlon');

    $options['operator'] = array('default' => 'in');

    $options['identifier'] = array('default' => 'dist');

    $options['value'] = array(
      'default' => array(
        'latitude' => '',
        'longitude' => '',
        'postal_code' => '',
        'country' => '',
        'search_distance' => 100,
        'search_distance_inner' => 50,
        'search_units' => 'mile',
      ),
    );
    return $options;
  }

  function admin_summary() {
    return '';
  }

  function operator_options() {
    return array(
      'in' => t('Within the selected proximity'),
      'out' => t('Not within the selected proximity'),
    );
  }

  function expose_form_left(&$form, &$form_state) {
    parent::expose_form_left($form, $form_state);
    $form['expose']['type'] = array(
      '#parents' => array('options', 'type'),
      '#type' => 'select',
      '#title' => t('Form mode'), // @@@ Less stupid title?
      '#options' => array(
        'latlon' => t('Latitude / Longitude input'),
        'postal' => t('Postal Code / Country'),
        'postal_default' => t('Postal Code (assume default country)'),
      ),
      //'#id' => 'edit-options-type',
      '#description' => t('FIXME'),
      '#default_value' => $this->options['type'],
    );
  }

  function value_form(&$form, &$form_state) {
    $val = $this->value;

    if (!empty($form_state['exposed'])) {
      $identifier = $this->options['expose']['identifier'];
      if (!isset($form_state['input'][$identifier])) {
        // We need to pretend the user already inputted the defaults, because
        // fapi will malfunction otherwise.
        $form_state['input'][$identifier] = $this->value;
      }
    }

    $form['value'] = array(
      '#tree' => TRUE,
    );

    $form['value']['latitude'] = array(
      '#type' => 'textfield',
      '#title' => t('Latitude'),
      '#default_value' => $this->value['latitude'],
      '#process' => array('views_process_dependency'),
      '#dependency' => array('edit-options-type' => array('latlon')),
    );
    $form['value']['longitude'] = array(
      '#type' => 'textfield',
      '#title' => t('Longitude'),
      '#default_value' => $this->value['longitude'],
      '#process' => array('views_process_dependency'),
      '#dependency' => array('edit-options-type' => array('latlon')),
    );

    $form['value']['postal_code'] = array(
      '#type' => 'textfield',
      '#title' => t('Postal code'),
      '#default_value' => $this->value['postal_code'],
      '#process' => array('views_process_dependency'),
      '#dependency' => array('edit-options-type' => array('postal', 'postal_default')),
    );

    $form['value']['country'] = array(
      '#type' => 'select',
      '#title' => t('Country'),
      '#options' => array('' => '') + location_get_iso3166_list(),
      '#default_value' => $this->value['country'],
      '#process' => array('views_process_dependency'),
      '#dependency' => array('edit-options-type' => array('postal')),
    );

    $form['value']['search_distance'] = array(
      '#type' => 'textfield',
      '#title' => t('Distance'),
      '#default_value' => $this->value['search_distance'],
    );
	
    $form['value']['search_distance_inner'] = array(
      '#type' => 'textfield',
      '#title' => t('Inner Distance to exclude (leave empty to ignore)'),
      '#default_value' => $this->value['search_distance_inner'],
    );

    $form['value']['search_units'] = array(
      '#type' => 'select',
      '#options' => array(
        'mile' => t('Miles'),
        'km' => t('Kilometers'),
      ),
      '#default_value' => $this->value['search_units'],
    );
  }

  function exposed_form(&$form, &$form_state) {
    parent::exposed_form($form, $form_state);
    $key = $this->options['expose']['identifier'];
    $type = $this->options['type'];

    // Remove unneeded fields when exposing the form.
    // It's shorter than redefining value_form.
    if ($type != 'latlon') {
      unset($form[$key]['latitude']);
      unset($form[$key]['longitude']);
    }
    if ($type != 'postal' && $type != 'postal_default') {
      unset($form[$key]['postal_code']);
    }
    if ($type != 'postal') {
      unset($form[$key]['country']);
    }
  }

  // Used from the distance field.
  function calculate_coords() {
    if (!empty($this->value['latitude']) && !empty($this->value['longitude'])) {
      // If there are already coordinates, there's no work for us.
      return TRUE;
    }
	// The following is included here in case this filter is used 
    // Get coordinates from session var created by search form
	if (!empty($_SESSION['listings']['targeted_search'])) {
	  if (is_numeric($_SESSION['listings']['targeted_search'])) {
        if (empty($this->value['country'])) $this->value['country'] = variable_get('location_default_country', 'nz');
		
		$this->value['postal_code'] = trim($_SESSION['listings']['targeted_search']);
        // Zip code lookup.
        if (!empty($this->value['country'])) {
          $coord = location_latlon_rough($this->value);
          if ($coord) {
            $this->value['latitude'] = $coord['lat'];
            $this->value['longitude'] = $coord['lon'];
			return TRUE;
          }
 	    }
	  }
	  else {
	    $city = explode(": ", $_SESSION['listings']['targeted_search']);
        $result = db_query("SELECT latitude, longitude FROM {zipcodes} WHERE LOWER(city)='%s' AND LOWER(state)='%s'", $city[0], $city[1]);
	  }
	}
	
    else {
	  if (module_exists('ad_geoip')) {
	    if (!function_exists('ad_geoip_city_code')) include(drupal_get_path('module', 'ad_geoip').'/ad_geoip.inc');
	    $city = ad_geoip_city_code();
	    $state = ad_geoip_region_code();
	    $country = ad_geoip_country_code();
	  }
	  $data = listing_location_validate_location($city, '', $state, $country);
		if ($data['count']==0 || $city=='' || !isset($city)) {
          $default = explode(": ",variable_get('listing_default_location', 'Chicago: IL'));
	      $city = trim($default[0]);
		  $state = trim($default[1]);
		  $country = variable_get('listing_default_country', 'nz');
	    }		
	  //$_SESSION['listings']['targeted_search'] = $city.': '.strtoupper($state);
	  $result = db_query("SELECT latitude, longitude FROM {zipcodes} WHERE LOWER(city)='%s' AND LOWER(state)='%s' AND LOWER(country)='%s'", strtolower($city), strtolower($state), strtolower($country));
	}
	$target = db_fetch_object($result);
	if (!empty($target->latitude) && !empty($target->longitude)) {
        $this->value['latitude'] = $target->latitude;
        $this->value['longitude'] = $target->longitude;
		return true;
	}
    else {
	    // If the city entered was not found or otherwise returned no coordinates then we don't do the view
		// We probably don't want to do any redirects in the filter
		//if (arg(0)!='listings') drupal_goto('default-listing');
        return false;
    }
 	
  }

  function query() {
    if (empty($this->value)) {
      return;
    }

    // Get coordinates from user city 	
	
    if (!$this->calculate_coords()) {
      // Distance set?
      if (!empty($this->value['search_distance'])) {
        // Hmm, distance set but unable to resolve coordinates.
        // Force nothing to match.
        $this->query->add_where($this->options['group'], "0");
      }
      return;
    }

    $this->ensure_my_table();

    $lat = $this->value['latitude'];
    $lon = $this->value['longitude'];
    $distance_meters = _location_convert_distance_to_meters($this->value['search_distance'], $this->value['search_units']);

    $latrange = earth_latitude_range($lon, $lat, $distance_meters);
    $lonrange = earth_longitude_range($lon, $lat, $distance_meters);

	if ($this->value['search_distance_inner']>0) {
      $inner_distance_meters = _location_convert_distance_to_meters($this->value['search_distance_inner'], $this->value['search_units']);
      $inner_latrange = earth_latitude_range($lon, $lat, $inner_distance_meters);
      $inner_lonrange = earth_longitude_range($lon, $lat, $inner_distance_meters);
      $this->query->add_where($this->options['group'], "$this->table_alias.latitude > %f AND $this->table_alias.latitude < %f AND $this->table_alias.longitude > %f AND $this->table_alias.longitude < %f AND (($this->table_alias.latitude < %f OR $this->table_alias.latitude > %f) OR ($this->table_alias.longitude < %f OR $this->table_alias.longitude > %f))", $latrange[0], $latrange[1], $lonrange[0], $lonrange[1], $inner_latrange[0], $inner_latrange[1], $inner_lonrange[0], $inner_lonrange[1]);
	
	}
    elseif ($this->operator == 'in') {
      $this->query->add_where($this->options['group'], "$this->table_alias.latitude > %f AND $this->table_alias.latitude < %f AND $this->table_alias.longitude > %f AND $this->table_alias.longitude < %f", $latrange[0], $latrange[1], $lonrange[0], $lonrange[1]);
	}
	else {
      $this->query->add_where($this->options['group'], "($this->table_alias.latitude < %f OR $this->table_alias.latitude > %f) OR ($this->table_alias.longitude < %f OR $this->table_alias.longitude > %f)", $latrange[0], $latrange[1], $lonrange[0], $lonrange[1]);
	}
  }
}